import logging
from functools import wraps
from typing import Callable, TypeVar, cast

from flask import Blueprint, current_app, request
from flask import jsonify

from airflow.patsnap.service import env_service
from airflow.models.idata_env import Env
from airflow.www.api import provide_user, exception_handle

log = logging.getLogger(__name__)

T = TypeVar("T", bound=Callable)  # pylint: disable=invalid-name


def requires_authentication(function: T):
    """Decorator for functions that require authentication"""

    @wraps(function)
    def decorated(*args, **kwargs):
        return current_app.api_auth.requires_authentication(function)(*args, **kwargs)

    return cast(T, decorated)


api_speech_env = Blueprint('api_speech_env', __name__)


# user route
@api_speech_env.route('/envs/<int:id>', methods=['GET'])
@exception_handle
def get_env(id):
    env = Env.get_env(id)
    return jsonify(code=0, message='ok', data=env.to_json())


@api_speech_env.route('/envs', methods=['GET'])
@exception_handle
def get_envs():
    page = request.values.get('page', 0, type=int)
    env_type = request.values.get("type", type=str, default=None)
    result = env_service.get_envs(page, env_type)
    return jsonify(code=0, message='ok', data=result)


@api_speech_env.route('/envs', methods=['POST'])
@provide_user
@exception_handle
def add_env(oa_user_name):
    env = request.json
    name = env['name']
    env_type = env['env_type']
    etl_path = env['etl_path']
    common_jar_path = env['common_jar_path']
    kafka_jar_path = env['kafka_jar_path']
    temporary_file_path = env['temporary_file_path']
    jdbc_jar_path = env['jdbc_jar_path']
    mongodb_jar_path = env['mongodb_jar_path']
    checkpoint_path = env['checkpoint_path']
    decoder_path = env['decoder_path']
    hive_jar_path = env['hive_jar_path']
    es_jar_path = env['es_jar_path']
    binary_path = env['binary_path']
    docker_image = env['docker_image']

    if name is None:
        log.error(
            "add_env params error name={%s}",name)
        return jsonify(code=400, message="add_projects params has Node,", data=None)
    env_service.add_env(name, env_type, etl_path, common_jar_path, kafka_jar_path, temporary_file_path, jdbc_jar_path, mongodb_jar_path,
                          checkpoint_path, decoder_path, hive_jar_path, es_jar_path, binary_path, docker_image)
    return jsonify(code=0, message='ok', data=None)


@api_speech_env.route('/envs/<int:id>', methods=['DELETE'])
@exception_handle
def delete_env(id):
    Env.delete_env(id)
    return jsonify(code=0, message='ok', data=None)


@api_speech_env.route('/envs', methods=['PUT'])
@exception_handle
@provide_user
def update_env(oa_user_name):
    env = request.json
    env_id = env['id']
    name = env['name']
    env_type = env['env_type']
    etl_path = env['etl_path']
    common_jar_path = env['common_jar_path']
    kafka_jar_path = env['kafka_jar_path']
    temporary_file_path = env['temporary_file_path']
    jdbc_jar_path = env['jdbc_jar_path']
    mongodb_jar_path = env['mongodb_jar_path']
    checkpoint_path = env['checkpoint_path']
    decoder_path = env['decoder_path']
    hive_jar_path = env['hive_jar_path']
    es_jar_path = env['es_jar_path']
    binary_path = env['binary_path']
    docker_image = env['docker_image']

    if env_id is None or name is None or env_type is None :
        log.error(
            "update_env params error env_id={%s},name={%s},env_type={%s}",
            env_id, name, env_type)
        return jsonify(code=400, message="update_project params has Node,", data=None)
    env_service.update_env(env_id, name, env_type, etl_path, common_jar_path, kafka_jar_path, temporary_file_path, jdbc_jar_path, mongodb_jar_path,
                             checkpoint_path, decoder_path, hive_jar_path, es_jar_path, binary_path, docker_image)
    return jsonify(code=0, message='ok', data=None)
